#include "module_window.h"
#include "ui_module_window.h"

#include <QDebug>

#include <QPainter>
#include <QGraphicsOpacityEffect>
#include <QGraphicsView>

#include "mainwindow.h"

#include "code/code_window.h"

#include "GlobalSingal.h"

#include <QMessageBox>
#include <QScrollArea>

module_window::module_window(Module_Data *data, QWidget *parent) :
    QFrame(parent),
    ui(new Ui::module_window)
{
    ui->setupUi(this);

    ui->graphicsView->setScene(this->scene);

    this->module_data = data;

}

void module_window::set_module_name(QString name)
{
    this->module_data->set_module_name(name);
}


void module_window::setLableName(QString name)
{
    this->set_module_name(name);

    emit changeLableName(name);
}

void module_window::add_child_module(Module_Data *data, QString name, QPointF point, bool add_child)
{
    Child_Module_Data *child_module_data = new Child_Module_Data(data, name, point);

    ChildModule *child = new ChildModule(DEFAULT_CHILD_MODULE_SIZE, child_module_data, this->master_module);

    child->setName(name, Qt::white);

    child->setPos(MODULE_DEFAULT_MARGIN, MODULE_DEFAULT_MARGIN);

    this->init_port(child, data);

    if (add_child)
        this->module_data->child_module.append(child_module_data);
}

void module_window::add_connect_line(ModuleLine *line)
{
    this->scene->addItem(line);
}


///---------------------------------------------------------------
/// 初始化

void module_window::init()
{
    this->init_module();
    this->init_child_module();
}

void module_window::init_module()
{
    QSizeF size = QSizeF(1100, 550);
    Module_Graph *module = new Module_Graph(size, this->module_data);

    module->setName(this->module_data->get_module_name(), Qt::black);

    this->master_module = module;

    this->init_port(module, module_data);

//    if (!module_data->child_module.isEmpty())
//        this->init_childModule(module, &module_data->child_module);

    this->scene->addItem(module);
}

//void module_window::init_childModule(Module_Graph *module, QList<Module_Data *> *data_list)
//{
//    for (int n(0); n < data_list->count(); n++) {
//        QSizeF size = QSizeF(300, 200);
//        ChildModule *child = new ChildModule(size, data_list->operator[](n), module);

//        child->setParentItem(module);
//        child->setPos(MODULE_DEFAULT_MARGIN, MODULE_DEFAULT_MARGIN);

//        this->init_port(child, data_list->at(n));

//        this->module_map.insert(child, data_list->at(n));
//    }
//}

void module_window::init_child_module()
{
    foreach(Child_Module_Data *child_data, this->module_data->child_module) {
        add_child_module(child_data->parent, child_data->instantiation_name, child_data->point);
    }
}

void module_window::init_port(Module_Graph *module, Module_Data *data)
{
    int input = data->get_input();
    int output = data->get_output();
    int inout = data->get_inout();

    int sum = output + inout;

    qreal port_left_x = -(module->boundingRect().width() / 16 / 2);
    qreal port_right_x = module->boundingRect().width() + port_left_x;

    qDebug() << "module window init port" << input << output << inout;
    ///---------------------------------------------------------------
    /// 创建Input Port

    for (int cycle(0); cycle < input ; cycle++) {
        ModulePort *port = new ModulePort(&data->ports.Input_List.operator[](cycle), module);

        port->setPos(port_left_x, port->compute_port_y(cycle, input));

        this->module_port_map.insert(port, data->ports.Input_List.at(cycle));
    }

    ///---------------------------------------------------------------
    /// 创建Output Port

    for (int cycle(0); cycle < output ; cycle++) {
        ModulePort *port = new ModulePort(&data->ports.Output_List.operator[](cycle), module);

        port->setPos(port_right_x, port->compute_port_y(cycle, sum));

        this->module_port_map.insert(port, data->ports.Output_List.at(cycle));
    }

    ///---------------------------------------------------------------
    /// 创建InOut Port

    int n = 0;

    for (int cycle(output); cycle < sum; cycle++) {
        ModulePort *port = new ModulePort(&data->ports.InOut_List.operator[](n), module);

        port->setPos(port_right_x, port->compute_port_y(cycle, sum));

        this->module_port_map.insert(port, data->ports.InOut_List.at(n));

        n++;
    }
}

///---------------------------------------------------------------
/// 获取

QString module_window::get_module_name()
{
    return this->module_data->get_module_name();
}

QString module_window::get_module_type()
{
    return this->module_data->get_module_type();
}

QString module_window::get_module_class()
{
    return this->module_data->get_module_class();
}

void module_window::make_code_window(Module_Data *data)
{
    code_window *c_window = new code_window(data);
    c_window->show();

}

module_window::~module_window()
{
    delete ui;
}





///---------------------------------------------------------------

Module_Graph::Module_Graph(QSizeF size, Module_Data *data, QGraphicsItem *parent) : QGraphicsItem(parent)
{
    Module_Graph();

    module_width = size.width();
    module_height = size.height();

    this->Data = data;
}

Module_Graph::Module_Graph(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    setAcceptedMouseButtons(Qt::LeftButton);
    setAcceptHoverEvents(true);
    setAcceptDrops(true);

    setFlags(QGraphicsItem::ItemIsSelectable);
}

Module_Graph::~Module_Graph()
{
    ;;
}

void Module_Graph::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setBrush(Qt::gray);
    painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿渲染

    painter->drawRoundedRect(boundingRect(), MODULE_DEFAULT_xRadius, MODULE_DEFAULT_yRadius);
}

QRectF Module_Graph::boundingRect() const
{
    return QRectF(0, 0, module_width, module_height);
}

void Module_Graph::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    make_module_property(this->Data);
    QGraphicsItem::mousePressEvent(event);
}

void Module_Graph::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    module_window::make_code_window(this->Data);
    QGraphicsItem::mouseDoubleClickEvent(event);
}

void Module_Graph::setName(QString name, QColor color)
{
    if (Name == nullptr)
        Name = new QGraphicsTextItem(this);

    Name->setDefaultTextColor(color);
    Name->setPlainText(name);

    QPointF p = this->boundingRect().center();
    p.setX(p.x() - Name->boundingRect().width() / 2);
    p.setY(p.y() - Name->boundingRect().height() / 2);
    Name->setPos(p);
}

void Module_Graph::make_module_property(Module_Data *data)
{
    module_propertys::delete_propertys();

    module_window_property *new_property = new module_window_property(data);
    connect(new_property, &module_window_property::changeLabelName, this, &Module_Graph::change_label);

    module_propertys::add_propertys(new_property);
}

void Module_Graph::change_label(QString arg1)
{
    setName(arg1, Qt::black);
}

///---------------------------------------------------------------


ChildModule::ChildModule(QSizeF size, Child_Module_Data *data, Module_Graph *parent) : Module_Graph(parent)
{

    module_width = size.width();
    module_height = size.height();

    setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges | QGraphicsItem::ItemClipsToShape);

    QGraphicsOpacityEffect *e = new QGraphicsOpacityEffect;
    e->setOpacity(0.7);
    setGraphicsEffect(e);

    module_parent = parent;

    setParentItem(module_parent);

    this->Data = data;
}

ChildModule::~ChildModule()
{
    ;;
}

void ChildModule::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setBrush(Qt::black);

    painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿渲染

    painter->drawRoundedRect(boundingRect(), MODULE_DEFAULT_xRadius, MODULE_DEFAULT_yRadius);
}

void ChildModule::change_label(QString arg1)
{
    setName(arg1, Qt::white);
}

void ChildModule::make_module_property()
{
    module_propertys::delete_propertys();

    module_window_property *new_property = new module_window_property(this->Data);
    connect(new_property, &module_window_property::changeLabelName, this, &ChildModule::change_label);

    module_propertys::add_propertys(new_property);
}

void ChildModule::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
//    if (scene()->collidingItems(this).isEmpty())
//        ;;

    QGraphicsItem::mouseMoveEvent(event);
}

void ChildModule::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    make_module_property();
    QGraphicsItem::mousePressEvent(event);
}

void ChildModule::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseDoubleClickEvent(event);
}

QVariant ChildModule::itemChange(GraphicsItemChange change, const QVariant &value)
{
//    if (scene()->collidingItems(this).isEmpty())
//        return QGraphicsItem::itemChange(change, value);

    if (change == ItemPositionChange && scene())
    {
        QPointF pos = value.toPointF();

        qreal width = this->boundingRect().width() + MODULE_DEFAULT_MARGIN;
        qreal height = this->boundingRect().height() + MODULE_DEFAULT_MARGIN;

        QRectF rect(QPointF(MODULE_DEFAULT_MARGIN, MODULE_DEFAULT_MARGIN), QPointF(module_parent->boundingRect().width() - width, module_parent->boundingRect().height() - height));

        if (!rect.contains(pos))
        {
            // Max 取 x 轴最小值，Min取 x 轴 最大值
            // right = x轴最大点
            // left = x轴最小点

            pos.setX(qMin(rect.right(), qMax(pos.x(), rect.left())));
            pos.setY(qMin(rect.bottom(), qMax(pos.y(), rect.top())));

            return pos;
        }
    }

    return QGraphicsItem::itemChange(change, value);
}

QPainterPath ChildModule::shape() const
{
    QPainterPath path;
    path.addRoundedRect(boundingRect(), 25, 25);
    return path;
}




ModulePort::ModulePort(PortAttribute *data, QGraphicsItem *parent) : Module_Graph(parent)
{
    QGraphicsOpacityEffect *e = new QGraphicsOpacityEffect;
    e->setOpacity(0.5);
    setGraphicsEffect(e);

    module = parent;

    this->module_width = module->boundingRect().width() / 16;
    this->module_height = module->boundingRect().height() / 16;

    this->setParentItem(parent);

    qDebug() << "make port "<< data->id << data->name << data->type;

    this->Data = data;

    setName(Data->name, Qt::white);
}

ModulePort::~ModulePort()
{
    ;;
}

void ModulePort::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setBrush(Qt::black);

    painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿渲染

    painter->drawRoundedRect(boundingRect(), 0, 0);
}

void ModulePort::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (GSingal.if_connect_line)
    {
        if(GSingal.if_end_connect_line)
        {
            GSingal.if_end_connect_line = false;
            GSingal.set_start_line(this);
        }
        else
        {
            if (GSingal.start_port == this)
                return;

            GSingal.if_end_connect_line = true;
            GSingal.set_end_line(this);
            GSingal.connect_line();
        }
    }

    make_port_property(this->Data);
    QGraphicsItem::mousePressEvent(event);
}


void ModulePort::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseDoubleClickEvent(event);
}


qreal ModulePort::compute_port_y(int num, int sum)
{
    return this->module->boundingRect().height() * (num + 1) / (sum + 1) - this->module_height / 2;
}

void ModulePort::make_port_property(PortAttribute *data)
{
    module_propertys::delete_propertys();

    module_port_property *new_property = new module_port_property(data);

    module_propertys::add_propertys(new_property);
}






ModuleLine::ModuleLine(QGraphicsItem *startItem, QGraphicsItem *endItem)
{
    _startItem = startItem;
    _endItem = endItem;
    setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
}

ModuleLine::~ModuleLine()
{
    ;;
}

QRectF ModuleLine::boundingRect() const
{
    return QRectF(_startItem->scenePos() - QPointF(10, 10), _endItem->scenePos() + QPointF(10, 10));
}

void ModuleLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPainterPath path;

    qDebug() <<  _startItem->shape();

    path.pointAtPercent(0);

    path.moveTo(_startItem->scenePos());

    path.cubicTo(_startItem->scenePos() + QPointF(100, 0), _endItem->scenePos() - QPointF(100, 0), _endItem->scenePos());

    QPen pen = painter->pen();
    QLinearGradient lineG(_startItem->scenePos(), _endItem->scenePos());

    lineG.setColorAt(0, Qt::yellow);
    lineG.setColorAt(0.5, Qt::red);
    lineG.setColorAt(1, Qt::blue);

    pen.setWidth(2);
    pen.setBrush(lineG);

    painter->setPen(pen);
    painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿渲染
    painter->drawPath(path);
}


ModuleScene::ModuleScene(QObject *parent) : QGraphicsScene(parent)
{

}

void ModuleScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
//    qDebug() << "Press Scene" << event->scenePos().x() << event->scenePos().y();

//    qreal x = event->scenePos().x();
//    qreal y = event->scenePos().y();

////    QTransform transform;
////    Module_Graph *item = dynamic_cast<Module_Graph *>(this->itemAt(QPointF(event->scenePos()), transform));

////    qDebug() << this->itemAt(x + 2, y + 2, QTransform());

//    if (ModulePort *port = qgraphicsitem_cast<ModulePort *>(this->itemAt(x + 2, y + 2, QTransform())))
//    {
//        qDebug() << "press port";
//    }

    QGraphicsScene::mousePressEvent(event);
}
















